
from psd_tools import PSDImage
from psd_tools.constants import ChannelID

import rpyc

import numpy as np

import bisect
import os

import time 
from PIL import Image
import numpy as np
from sklearn.neighbors import KDTree


from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import numpy as np
#import cv2
import os
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import (QApplication, QWidget, QPushButton, QLabel, QLineEdit, QGridLayout, QMessageBox)
import sys

 

#index  界定的范围  要找的index数组长度
def GetNearIndex(curr_idx, size,lenth):
    left = size/2
    right = size/2
    left_idx = curr_idx
    right_idx = curr_idx
    while left > 0 and left_idx > 0 :
        left = left -1
        left_idx = left_idx - 1
    while right_idx < lenth  and right + left > 0:
        right_idx = right_idx + 1
        right = right - 1
    return  left_idx, right_idx 
        



def GetNearst(element, pixel_index):
    # Use binary search to find index of nearest value in B_sorted
    idx = bisect.bisect_left(pixel_index, element, lo=0, hi=len(pixel_index))
    if idx == 0:
        print(pixel_index[idx])
    elif idx == len(pixel_index):
        print(pixel_index[-1])
    else:
        # Compare two closest values in B_sorted
        if element - pixel_index[idx-1] < pixel_index[idx] - element:
            print(pixel_index[idx-1])
        else:
            print(pixel_index[idx])








conn = rpyc.connect("152.136.196.35", 9002)
service = conn.root



config = ['skin', 'ground', 'mouth']



skin_lines = []
ground_lines = []
mouth_lines = []
curr_psd_path = ""
curr_psd_file  = ""




def rpyc_deep_copy(obj):
    """
    Makes a deep copy of netref objects that come as a result of RPyC remote method calls.
    When RPyC client obtains a result from the remote method call, this result may contain
    non-scalar types (List, Dict, ...) which are given as a wrapper class (a netref object). 
    This class does not have all the standard attributes (e.g. dict.tems() does not work) 
    and in addition the objects only exist while the connection is active (are weekly referenced). 
    To have a retuned value represented by python's native datatypes and to by able to use it 
    after the connection is terminated, this routine makes a recursive copy of the given object. 
    Currently, only `list` and `dist` types are supported for deep_copy, but other types may be 
    added easily.
    Note there is allow_attribute_public option for RPyC connection, which may solve the problem too, 
    but it have not worked for me.
    Example:
        s = rpyc.connect(host1, port)
        result = rpyc_deep_copy(s.root.remote_method())
        # if result is a Dict:
        for k,v in result.items(): print(k,v) S
    """
    if (isinstance(obj, list)):
        copied_list = []
        for value in obj: copied_list.append(rpyc_deep_copy(value))
        return copied_list
    elif (isinstance(obj, dict)):
        copied_dict = {}
        for key in obj: copied_dict[key] = rpyc_deep_copy(obj[key])
        return copied_dict
    else:
        return obj




def request_config():
    receiver = []
    receiver.append(service.line("skin") )
    receiver.append(service.line("ground") )
    receiver.append(service.line("mouth") )
    parse_config = []
    for ele in receiver:
        curr_parse = []
        curr_color = ele.split("@")
        header = 0;
        for ele in curr_color :
            if header == 0 :
                header = 1
                continue
            ele = ele.replace("\t" , "")
            ele = ele.replace("\n" , "")
            ele = list(map(int, ele.split(",")))
            curr_parse.append(ele)
        parse_config.append(curr_parse)
    return parse_config

config_receiver = request_config()


skin_lines  =  config_receiver[0]
ground_lines  =  config_receiver[1]
mouth_lines  =  config_receiver[2]





ground_tree = KDTree(ground_lines)
mouth_tree = KDTree(mouth_lines)
skin_tree = KDTree(skin_lines)



def GetNearst(element, pixel_index):
    # Use binary search to find index of nearest value in B_sorted
    idx = bisect.bisect_left(pixel_index, element)
    if idx == 0:
        #print(pixel_index[idx])
        return pixel_index[idx],idx
    elif idx == len(pixel_index):
        return pixel_index[-1], -1
    else:
        # Compare two closest values in B_sorted
        if element - pixel_index[idx-1] < pixel_index[idx] - element:
            return pixel_index[idx-1] , idx -1
        else:
            return pixel_index[idx], idx



def copy_to_whole_image(curr_layer, w, h):
    x_begin = curr_layer.bbox[0]
    y_begin = curr_layer.bbox[1]
    x_end = curr_layer.width + x_begin
    y_end = curr_layer.height + y_begin
    if w == x_end and h == y_end:
        return  curr_layer.topil()

    curr_img = Image.new('RGBA', (w, h), (0,0,0,0))
    image_from_layer = curr_layer.topil()
    for i in  range(0, curr_img.width):
        if i <= x_begin or i >= x_end:
            continue
        for j in range ( 0 , curr_img.height):
            if j <= y_begin or j>= y_end:
                continue
            pix_x = i - x_begin
            pix_y = j - y_begin
            pix = image_from_layer.getpixel( (pix_x , pix_y ) )
            curr_img.putpixel((i ,j),  pix  );
    #curr_img.save("test_layer.png")
    return curr_img



def proc_layer(curr_layer, curr_tree, curr_dict, curr_layer_num,  png_index):
    src_size = curr_layer.parent.size
    image = copy_to_whole_image(curr_layer, src_size[0], src_size[1])

    
    for w in range(0,image.width ):
        for h in range (0 , image.height):
             pix = image.getpixel((w,h))
             if pix[3] == 0:
                 continue
             target_color = np.array([pix[0], pix[1], pix[2]])
             dist, ind = curr_tree.query([target_color], k = 1)
             idx = ind[0][0]
             k_pix = curr_dict[idx]
             image.putpixel((w, h), tuple(k_pix))
    file_name = curr_psd_file[:-4]
    #curr_dir = os.path.abspath(os.getcwd())
    #curr_dir = curr_dir.replace("\\" , "//")
    image.save(curr_psd_path + "/" + file_name +"-" + str(png_index) + ".png")




def proc_psd(psd):
    curr_layer = 0

    for layer in psd:
        
        print(layer)
        #proc_watch(layer)


        print(layer.has_mask())
        image = layer.topil()
        print(image.mode)
        red = layer.topil(ChannelID.CHANNEL_0)
        green = layer.topil(ChannelID.CHANNEL_1)
        blue = layer.topil(ChannelID.CHANNEL_2)
        if curr_layer == 0:
            #zero_psd(layer)

            curr_layer = curr_layer + 1
            #continue
            proc_layer(layer, ground_tree, ground_lines,  curr_layer, 1)
        elif curr_layer == 1:
            #zero_psd(layer)

            curr_layer = curr_layer + 1
            #continue
            proc_layer(layer, skin_tree, skin_lines,  curr_layer, 2)
            proc_layer(layer, ground_tree, ground_lines,  curr_layer, 20)
        elif curr_layer == 2:
            curr_layer = curr_layer + 1
            proc_layer(layer, mouth_tree, mouth_lines, curr_layer, 3)
        elif curr_layer == 3:
            curr_layer = curr_layer + 1
            proc_layer(layer, ground_tree, ground_lines, curr_layer, 4)







class Ui_Dialog(object):
    def setupLogin(self,Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.setEnabled(True)


    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.setEnabled(True)
        Dialog.resize(959/3, 539/3)
        Dialog.setMinimumSize(QtCore.QSize(959/3, 539/3))
        Dialog.setMaximumSize(QtCore.QSize(1920/3, 1080/3))
        self.label = QtWidgets.QLabel(Dialog)
        self.label.setGeometry(QtCore.QRect(0, 0, 959/3, 539/3))
        self.label.setAcceptDrops(False)
        self.label.setScaledContents(False)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.label.setObjectName("label")

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Psd"))
        self.label.setText(_translate("Dialog", "拖拽psd文件或者目录至此处"))

#读取中文路径
def cv_imread(file_path):
    cv_img = cv2.imdecode(np.fromfile(file_path,dtype=np.uint8),-1)
    return cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)

class mwindow(QWidget, Ui_Dialog):
    def __init__(self):
        super(mwindow, self).__init__()
        self.setupUi(self)
        # 调用Drops方法
        self.setAcceptDrops(True)
        # 图片
        self.img = None
    def merg_svg(self,dir_List):
        print("merge")

    # 鼠标拖入事件
    def dragEnterEvent(self, evn):
        # print('鼠标拖入窗口了')
        # 鼠标放开函数事件
        evn.accept()
 
    # 鼠标放开执行
    def dropEvent(self, evn):
        global curr_psd_file
        global curr_psd_path
        # 判断文件类型
        if evn.mimeData().hasUrls():
            # 获取文件路径
            file_path =  evn.mimeData().urls()[0].toLocalFile()
            url_length = len(evn.mimeData().urls())
            
            if url_length > 1:
                #y拖入的是文件

                dir_path = os.path.dirname(evn.mimeData().urls()[0].toLocalFile())
                psd_list = []
                path_len = len(dir_path)
                for idx in range(0, url_length):
                    curr_file = evn.mimeData().urls()[idx].toLocalFile()
                    file_type = curr_file[-3:]
                    if file_type == "psd":
                        psd_list.append(curr_file)
                if len(psd_list) > 0 :
                    curr_psd_path = dir_path
                    for ele in psd_list:
                        psd = PSDImage.open(ele)
                        proc_psd(psd)
            else:
                is_dot = file_path[-4: -3]
                if is_dot == ".":
                    file_type = file_path[-3:]
                    if  file_type == "psd":
                        print("svg")
                        dir_path = os.path.dirname(evn.mimeData().urls()[0].toLocalFile())
                        single_file = evn.mimeData().urls()[0].toLocalFile()
                        curr_psd_file = single_file.split("/")[-1]
                        curr_psd_path = dir_path
                        psd = PSDImage.open(single_file)
                        proc_psd(psd)

                        return 
                    else:
                        return 

                path_len = len(file_path)
                file = file_path
                for root, dirs, files in os.walk(file):
                        if root != file:
                            break
                psd_list = []
                for file in files:
                     path = os.path.join(root, file)
                     file_type = path[-3:]
                     if file_type == "psd":
                         psd_list.append(path)
                     print(path)
                dir_path = evn.mimeData().urls()[0].toLocalFile()
                curr_psd_path = dir_path
                for ele in psd_list:
                    ele = ele.replace("\\", "/")
                    curr_psd_file = ele.split('/')[-1]
                    psd = PSDImage.open(ele)
                    proc_psd(psd)

            # opencv 转qimage
            #qimg = QImage(self.img.data, self.img.shape[1], self.img.shape[0], self.img.shape[1]*self.img.shape[2],QImage.Format_RGB888)
            # 显示图片 自适应
            #self.label.setPixmap(QPixmap.fromImage(qimg).scaled(self.label.width(), self.label.height(), Qt.KeepAspectRatio))
        # print('鼠标放开了')
 
    def dragMoveEvent(self, evn):
        pass
        # print('鼠标移入')



class LoginForm(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('Login Form')
        self.resize(500, 120)       
        layout = QGridLayout()      
        label_name = QLabel('<font size="4"> Username </font>')
        self.lineEdit_username = QLineEdit()
        self.lineEdit_username.setPlaceholderText('Please enter your username')
        layout.addWidget(label_name, 0, 0)
        layout.addWidget(self.lineEdit_username, 0, 1)      
        label_password = QLabel('<font size="4"> Password </font>')
        self.lineEdit_password = QLineEdit()
        self.lineEdit_password.setPlaceholderText('Please enter your password')
        layout.addWidget(label_password, 1, 0)
        layout.addWidget(self.lineEdit_password, 1, 1)      
        button_login = QPushButton('Login')
        button_login.clicked.connect(self.check_password)
        layout.addWidget(button_login, 2, 0, 1, 2)
        layout.setRowMinimumHeight(2, 75)       
        self.setLayout(layout)

    def check_password(self):
        msg = QMessageBox() 
        print(service.tocken('admin', '1234564'))  # prints 5
        print(service.tocken('admin', '123456'))  # prints 5
        if service.tocken(self.lineEdit_username.text(), self.lineEdit_password.text()):
            msg.setText('Success')
            deal_win.show()
            self.close()
            #msg.exec_()
            #app.quit()
        else:
           msg.setText('Incorrect Password')
           msg.exec_()
if __name__ == '__main__':
    app=QApplication(sys.argv)
    #初始化窗口
    #m=mwindow()
    #m.show()
    #sys.exit(app.exec_())
    deal_win = mwindow()
    #deal_win.show()
    m = LoginForm()
    m.show()
    sys.exit(app.exec_())

